%%{
  machine JSON;
  alphtype int;
# Data members.
  false		 = 'false' @pushFalse;
  nul		 = 'null' @pushNull;
  true		 = 'true' @pushTrue;

  int		 = '0' | ([1-9] digit*);
  exp		 = [eE] [\-+]? digit+;
  fract		 = '.' digit+;
  number	 = ('-'? int fract? exp?) >startNum %pushNum ;
  
  unescaped	 = 0x20 | 0x21 | (0x23 .. 0x5b) | (0x5d .. 0xffff);
  escaped	 = '\\' (
			   '\"' @unescapeQuote			|
			   '\\' @unescapeBackslash		|
			   '/'  @unescapeSlash			|
			   'b'  @unescapeBackspace		|
			   'f'  @unescapeFormfeed		|
			   'n'  @unescapeNewline		|
			   'r'  @unescapeCarriageReturn	|
			   't'  @unescapeTab			|
			   'u' xdigit{4} @unescapeUnicode);
  char		 = unescaped | escaped;

# We have the same match for keys in objects, to simplify the actions.
  string	 = '"' @startString char* '"' @pushString;
  key		 = '"' @startKey    char* '"' @pushKey;

  dataValue	 = false | nul | true | number | string;
  
# Overall structural definitions
# array and object representations call machines, they require a stack
  arrayInit	     = '[' @{fcall array;};
  objectInit 	 = '{' @{fcall object;};

  ws		 = [ \t\r\n]*;
  value		 = dataValue | arrayInit | objectInit;

  member	 = key ws ':' ws value;
  members	 = member ws (',' ws member ws)* ;
  values	 = value ws (',' ws value ws)*;

  object	:= ( ws members? >startObject '}' @endObject @{fret;}) $!report $*breakOnEvent;
  array		:= ( ws values?  >startArray  ']' @endArray  @{fret;}) $!report $*breakOnEvent; 
  main		:= (ws (objectInit | arrayInit)) ws
  				$!report $*breakOnEvent; 		
}%%
